package eu.whowie.jast.server.web;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.Form;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.ProgressIndicator;
import com.vaadin.ui.SplitPanel;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Tree;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

import eu.whowie.jast.remote.JastClientCallbackHandler;
import eu.whowie.jast.remote.YastServer;
import eu.whowie.jast.server.ContextChangeListener;

public class JastApplication extends Application implements
		ServerSelectedListener, ContextChangeListener {

	private PersonList personList;
	private PersonForm personForm;
	private HorizontalLayout toolBarComponent;

	private SearchView searchView = null;
	private Map<YastServer, YastServerUIComponent> serverMap = new HashMap<YastServer, YastServerUIComponent>();

	private YastServerUIComponent selectedServer = null;

	private ApplicationContext context = null;

	private Layout mainScreen;
	private VerticalLayout mainLayout;
	private ComponentContainer currentLayout;

	@Override
	public void init() {
		initContext();
		initLayout();

		// install automatic refresher
		ProgressIndicator poller = new ProgressIndicator();
		poller.addStyleName("invisible");
		toolBarComponent.addComponent(poller);

		readData();

	}

	private void readData() {
		List<YastServer> servers = context.getConnectedServers();
		for (YastServer yastServer : servers) {
			serverConnected(yastServer);
		}
	}

	private void initContext() {
		this.context = ApplicationContext.getContext();
		context.addContextChangeListener(this);
	}

	private void initLayout() {
		setMainWindow(new Window("JAST Vaadin application"));

		mainScreen = new VerticalLayout();
		mainScreen.addComponent(new Label("Hello on Jast screen"));

		mainLayout = new VerticalLayout();
		mainLayout.setSizeFull();
		mainLayout.addComponent(createToolbar());
		setMainScreen(mainScreen);
		getMainWindow().setContent(mainLayout);

	}

	private HorizontalLayout createToolbar() {
		if (toolBarComponent == null) {
			toolBarComponent = new HorizontalLayout();
			Button info = new Button("Info");
			info.addListener(new ClickListener() {

				/**
				 * 
				 */
				private static final long serialVersionUID = 2066391021326191952L;

				@Override
				public void buttonClick(ClickEvent event) {
					setMainScreen(mainScreen);
				}
			});
			toolBarComponent.addComponent(info);
		}
		return toolBarComponent;

	}

	private void setMainScreen(ComponentContainer abstractComponentContainer) {
		if (currentLayout != null)
			mainLayout.removeComponent(currentLayout);

		currentLayout = abstractComponentContainer;
		mainLayout.addComponent(abstractComponentContainer, 1);
		mainLayout.setExpandRatio(abstractComponentContainer, 1);
	}

	public PersonContainer getDataSource() {

		return PersonContainer.createWithTestData();
	}

	@Override
	public void serverSelected(YastServerUIComponent ui) {
		selectedServer = ui;
		setMainScreen(ui.getMainUI());

	}

	@Override
	public void serverConnected(YastServer server) {
		/**
		 * server is not enough, we need to get call back handler, so we can
		 * start modules
		 */
		JastClientCallbackHandler handler = context.getJastRmiServer().lookup(
				server.getCallBackJNDIName(), JastClientCallbackHandler.class);

		YastServerUIComponent ui = new YastServerUIComponent(server, handler);
		Button button = ui.getSelectButton();
		button.addListener(new SelectServerClickListener(ui, this));
		this.serverMap.put(server, ui);

		toolBarComponent.addComponent(button);
	}

	@Override
	public void serverDisconnected(YastServer server) {
		YastServerUIComponent ui = this.serverMap.remove(server);
		Button button = ui.getSelectButton();
		button.setEnabled(false);
		// toolBarComponent.removeComponent(button);

	}
}

class NavigationTree extends Tree {
	public static final Object SHOW_ALL = "Show all";
	public static final Object SEARCH = "Search";

	public NavigationTree() {
		addItem(SHOW_ALL);
		addItem(SEARCH);
	}
}

class ListView extends SplitPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public ListView() {
	}
}

class PersonList extends Table {
	public PersonList(JastApplication app) {
		setSizeFull();
		setContainerDataSource(app.getDataSource());
		setVisibleColumns(PersonContainer.NATURAL_COL_ORDER);
		setColumnHeaders(PersonContainer.COL_HEADERS_ENGLISH);
		addListener((Property.ValueChangeListener) app);
		addListener((ItemClickListener) app);
		setSelectable(true);
		setNullSelectionAllowed(false);
	}
}

class PersonForm extends Form implements ClickListener {
	private Button save = new Button("Save", (ClickListener) this);
	private Button cancel = new Button("Cancel", (ClickListener) this);
	private Button edit = new Button("Edit", (ClickListener) this);

	public PersonForm() {
		addField("First Name", new TextField("First Name"));
		addField("Last Name", new TextField("Last Name"));

		setWriteThrough(false);

		HorizontalLayout footer = new HorizontalLayout();
		footer.setSpacing(true);
		footer.addComponent(save);
		footer.addComponent(cancel);
		footer.addComponent(edit);
		footer.setVisible(true);

		setFooter(footer);

	}

	@Override
	public void buttonClick(ClickEvent event) {
		System.out.println("button clicked " + event);

	}
}

class HelpWindow extends Window {
	private static final String HELP_HTML_SNIPPET = "This is "
			+ "an application built during <strong><a href=\""
			+ "http://dev.vaadin.com/\">Vaadin</a></strong> "
			+ "tutorial. Hopefully it doesn't need any real help.";

	public HelpWindow() {
		setCaption("Address Book help");
		addComponent(new Label(HELP_HTML_SNIPPET, Label.CONTENT_XHTML));
	}
}

class SharingOptions extends Window {
	public SharingOptions() {
		/*
		 * Make the window modal, which will disable all other components while
		 * it is visible
		 */
		setModal(true);
		/* Make the sub window 50% the size of the browser window */
		setWidth("50%");
		/*
		 * Center the window both horizontally and vertically in the browser
		 * window
		 */
		center();

		setCaption("Sharing options");
		addComponent(new Label(
				"With these setting you can modify contact sharing "
						+ "options. (non-functional, example of modal dialog)"));
		addComponent(new CheckBox("Gmail"));
		addComponent(new CheckBox(".Mac"));
		Button close = new Button("OK");
		addComponent(close);
	}
}

class PersonContainer extends BeanItemContainer<Person> implements Serializable {
	public static final Object[] NATURAL_COL_ORDER = new Object[] {
			"firstName", "lastName", "email", "phoneNumber", "streetAddress",
			"postalCode", "city" };
	public static final String[] COL_HEADERS_ENGLISH = new String[] {
			"First name", "Last name", "Email", "Phone number",
			"Street Address", "Postal Code", "City" };

	public PersonContainer() throws InstantiationException,
			IllegalAccessException {
		super(Person.class);
	}

	public static PersonContainer createWithTestData() {
		final String[] fnames = { "Peter", "Alice", "Joshua", "Mike", "Olivia",
				"Nina", "Alex", "Rita", "Dan", "Umberto", "Henrik", "Rene",
				"Lisa", "Marge" };
		final String[] lnames = { "Smith", "Gordon", "Simpson", "Brown",
				"Clavel", "Simons", "Verne", "Scott", "Allison", "Gates",
				"Rowling", "Barks", "Ross", "Schneider", "Tate" };
		final String cities[] = { "Amsterdam", "Berlin", "Helsinki",
				"Hong Kong", "London", "Luxemburg", "New York", "Oslo",
				"Paris", "Rome", "Stockholm", "Tokyo", "Turku" };
		final String streets[] = { "4215 Blandit Av.", "452-8121 Sem Ave",
				"279-4475 Tellus Road", "4062 Libero. Av.", "7081 Pede. Ave",
				"6800 Aliquet St.", "P.O. Box 298, 9401 Mauris St.",
				"161-7279 Augue Ave", "P.O. Box 496, 1390 Sagittis. Rd.",
				"448-8295 Mi Avenue", "6419 Non Av.",
				"659-2538 Elementum Street", "2205 Quis St.",
				"252-5213 Tincidunt St.", "P.O. Box 175, 4049 Adipiscing Rd.",
				"3217 Nam Ave", "P.O. Box 859, 7661 Auctor St.",
				"2873 Nonummy Av.", "7342 Mi, Avenue",
				"539-3914 Dignissim. Rd.", "539-3675 Magna Avenue",
				"Ap #357-5640 Pharetra Avenue", "416-2983 Posuere Rd.",
				"141-1287 Adipiscing Avenue", "Ap #781-3145 Gravida St.",
				"6897 Suscipit Rd.", "8336 Purus Avenue", "2603 Bibendum. Av.",
				"2870 Vestibulum St.", "Ap #722 Aenean Avenue",
				"446-968 Augue Ave", "1141 Ultricies Street",
				"Ap #992-5769 Nunc Street", "6690 Porttitor Avenue",
				"Ap #105-1700 Risus Street",
				"P.O. Box 532, 3225 Lacus. Avenue", "736 Metus Street",
				"414-1417 Fringilla Street", "Ap #183-928 Scelerisque Road",
				"561-9262 Iaculis Avenue" };
		PersonContainer c = null;
		Random r = new Random(0);
		try {
			c = new PersonContainer();
			for (int i = 0; i < 100; i++) {
				Person p = new Person();
				p.setFirstName(fnames[r.nextInt(fnames.length)]);
				p.setLastName(lnames[r.nextInt(lnames.length)]);
				p.setCity(cities[r.nextInt(cities.length)]);
				p.setEmail(p.getFirstName().toLowerCase() + "."
						+ p.getLastName().toLowerCase() + "@vaadin.com");
				p.setPhoneNumber("+358 02 555 " + r.nextInt(10) + r.nextInt(10)
						+ r.nextInt(10) + r.nextInt(10));
				int n = r.nextInt(100000);
				if (n < 10000) {
					n += 10000;
				}
				p.setPostalCode(n);
				p.setStreetAddress(streets[r.nextInt(streets.length)]);
				c.addItem(p);
			}
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return c;
	}
}

class SearchView extends Panel {
	public SearchView(final JastApplication app) {
		setCaption("Search contacts");
		setSizeFull();
	}
}
